package com.boil.qz.safekavass.service;

import com.boil.exception.UnauthorizedException;
import com.boil.pojo.ResultVo;
import com.boil.qz.safekavass.dao.MybatisDao;
import com.boil.qz.safekavass.model.*;
import com.boil.qz.safekavass.pojo.LoginUserVo;
import com.boil.qz.safekavass.repository.LoginUserRepository;
import com.boil.qz.safekavass.web.request.param.PasswdParam;
import com.boil.qz.safekavass.web.request.param.UpdateLoginUserParam;
import com.boil.qz.safekavass.web.request.param.UpdateLoginUserParam2;
import com.boil.util.Constants;
import com.boil.util.Page;
import com.boil.util.ShiroUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Iterator;

/**
 * Created by ChenYong on 2017-04-11.
 * <br>
 * 用户 Service。
 */
@Service
public class LoginUserService extends JpaRepositoryService<LoginUser, Long> {
    /**
     * 注入 Mybatis Dao
     */
    @Autowired
    private MybatisDao mybatisDao;
    /**
     * 注入登录用户实体仓库
     */
    @Autowired
    private LoginUserRepository loginUserRepository;
    /**
     * 注入举报 Service
     */
    @Autowired
    private ReportResService reportResService;

    /**
     * 根据登录 ID 查询用户。
     *
     * @param loginid 登录 ID
     * @return 用户实例
     */
    public LoginUser findByLoginid(String loginid) {
        return loginUserRepository.findByLoginid(loginid);
    }

    /**
     * 分页查询用户。
     *
     * @param page 分页实例
     */
    public void findInPage(Page<LoginUserVo> page) {
        mybatisDao.selectInPage("loginUserVoNs.findInPage", page);
    }

    /**
     * 更新我的信息。
     *
     * @param param 更新用户的请求参数
     */
    public LoginUser updateMy(UpdateLoginUserParam param) {
        // 获取登录用户的操作信息
        Subject subject = SecurityUtils.getSubject();
        // 获取登录用户的 Session
        Session session = subject.getSession();
        // 获取登录用户
        LoginUser loginUser = (LoginUser) session.getAttribute(Constants.LOGIN_USER);
        // 查询我的信息
        LoginUser my = findOne(loginUser.getId());

        BeanUtils.copyProperties(param, my);

        // 更新 Session 中的用户信息
        session.setAttribute(Constants.LOGIN_USER, my);

        return my;
    }

    /**
     * 更新用户信息。
     *
     * @param param 更新用户的请求参数
     */
    public LoginUser update(UpdateLoginUserParam2 param) {
        // 查询我的信息
        LoginUser user = findOne(param.getId());

        BeanUtils.copyProperties(param, user);

        // 获取登录用户的操作信息
        Subject subject = SecurityUtils.getSubject();
        // 获取登录用户的 Session
        Session session = subject.getSession();
        // 获取登录用户
        LoginUser loginUser = (LoginUser) session.getAttribute(Constants.LOGIN_USER);

        // 更新 Session 中的用户信息
        if (loginUser.getId() == user.getId()) {
            session.setAttribute(Constants.LOGIN_USER, user);
        }

        return user;
    }

    /**
     * 更新我的密码。
     *
     * @param resultVo 结果 Vo
     * @param param    更新密码的请求参数
     */
    public void updateMyPasswd(ResultVo resultVo, PasswdParam param) {
        // 获取登录用户的操作信息
        Subject subject = SecurityUtils.getSubject();
        // 获取登录用户的 Session
        Session session = subject.getSession();
        // 获取登录用户
        LoginUser loginUser = (LoginUser) session.getAttribute(Constants.LOGIN_USER);

        // 查询我的信息
        LoginUser my1 = findOne(loginUser.getId());

        // 旧密码正确
        if (my1.getPwd().equals(ShiroUtils.passwd2Md5(param.getOldPasswd()))) {
            my1.setPwd(ShiroUtils.passwd2Md5(param.getNewPasswd()));

            resultVo.setResultCode(Constants.SUCCESS);
            resultVo.setResultMsg(Constants.UPDATE_PASSWD_SUCESS_MSG);

            // 旧密码不正确
        } else {
            resultVo.setResultCode(Constants.OLD_PASSWD_ERROR);
            resultVo.setResultMsg(Constants.OLD_PASSWD_ERROR_MSG);
        }
    }

    /**
     * 登录验证。
     *
     * @param resultVo          结果 Vo
     * @param shiroLoginFailure Shiro 登录失败信息
     * @param account           账号
     */
    public void doLogin(ResultVo resultVo, String shiroLoginFailure, String account) {
        resultVo.setResult(account);

        // 登录账号不存在
        if (UnknownAccountException.class.getName().equals(shiroLoginFailure)) {
            resultVo.setResultCode(Constants.LOGIN_ACCOUNT_NOT_EXIST);
            resultVo.setResultMsg(Constants.LOGIN_ACCOUNT_NOT_EXIST_MSG);

            log.error("登录账号：{}--->Shiro 登录认证失败，原因是：账号不存在（{}）。", account, shiroLoginFailure);

            // 登录密码错误
        } else if (IncorrectCredentialsException.class.getName().equals(shiroLoginFailure)) {
            resultVo.setResultCode(Constants.LOGIN_PASSWD_ERROR);
            resultVo.setResultMsg(Constants.LOGIN_PASSWD_ERROR_MSG);

            log.error("登录账号：{}--->Shiro 登录认证失败，原因是：密码错误（{}）。", account, shiroLoginFailure);

            // 系统出现异常
        } else {
            resultVo.setResultCode(Constants.SYS_ERROR);
            resultVo.setResultMsg(Constants.SYS_ERROR_MSG);

            log.error("登录账号：{}--->Shiro 登录认证失败，原因是：系统出现异常（{}）。", account, shiroLoginFailure);
        }
    }

    /**
     * 根据用户 ID 删除用户。
     *
     * @param id 用户 ID
     */
    public void deleteById(long id) {
        // 用户【超级管理员】禁止删除
        if (id == Constants.VALUE_L_1) {
            throw new UnauthorizedException("用户【超级管理员】禁止删除");
        }

        // 查询用户
        LoginUser loginUser = findOne(id);

        // 解除用户与角色的关联关系
        loginUser.getRoles().clear();

        // 解除用户与首页广告的关联关系
        Iterator<HomeAdvert> homeAdvertIterator = loginUser.getHomeAdverts().iterator();
        while (homeAdvertIterator.hasNext()) {
            HomeAdvert homeAdvert = homeAdvertIterator.next();
            homeAdvert.setLoginUser(null);
        }

        // 解除用户与通知的关联关系
        Iterator<Notice> noticeIterator = loginUser.getNotices().iterator();
        while (noticeIterator.hasNext()) {
            Notice notice = noticeIterator.next();
            notice.setLoginUser(null);
        }

        // 解除用户与学习动态的关联关系
        Iterator<LearnDym> learnDymIterator = loginUser.getLearnDyms().iterator();
        while (learnDymIterator.hasNext()) {
            LearnDym learnDym = learnDymIterator.next();
            learnDym.setLoginUser(null);
        }

        // 解除用户与学习资料的关联关系
        Iterator<LearnFileData> learnFileDataIterator = loginUser.getLearnFileData().iterator();
        while (learnFileDataIterator.hasNext()) {
            LearnFileData learnFileData = learnFileDataIterator.next();
            learnFileData.setLoginUser(null);
        }

        // 解除用户与举报的管理关系
        reportResService.updateReportResRecordByUserId(loginUser.getId());

        // 删除用户
        delete(loginUser);
    }
}